from src.core.util.util import mkdir, get_default_tasks, get_user_tasks, write_file
from src.core.util import log
import pymysql as pm
from time import time


def __verify_config__(config: dict) -> None:
    log.info('Starting verifying config...')
    keys = ['ds.host', 'ds.username', 'ds.password', 'ds.schema', 'ds.table']
    for key in keys:
        if key not in config:
            raise KeyError('Config key missing "{}", please add it in config.properties'.format(key))
    log.info('Config verified!')


class CodeGenerator(object):
    """
    code generator. It has a inner state "data" containing query result.
    """
    FILE_PATH_PREFIX: str = 'out/'

    def __init__(self, config):
        self.__data: list = []
        __verify_config__(config)
        self.__load_table_info__(config)

    def __load_table_info__(self, config: dict) -> None:
        """
        read config from a dict, connect to db, then save query result to inner state.
        :param config: db connection configuration
        """
        host = config['ds.host']
        username = config['ds.username']
        password = config['ds.password']
        schema = config['ds.schema']
        table = config['ds.table']
        try:
            log.info('Connecting to schema/table: {}/{}'.format(schema, table))
            with pm.connect(host=host, user=username, password=password, database=schema) as conn:
                log.info('Database connect success!')
                with conn.cursor() as cursor:
                    log.info('Loading data...')
                    cursor.execute(
                        'SELECT COLUMN_NAME, DATA_TYPE, COLUMN_COMMENT \
                         FROM INFORMATION_SCHEMA.COLUMNS \
                         WHERE table_name = %s \
                           AND table_schema = %s',
                        (table, schema))
                    self.__data = cursor.fetchall()
                    log.info('Read {} record(s).'.format(len(self.__data)))
        except Exception as e:
            log.error('Database connection failed, please check your configuration.')
            raise e

    def do_tasks(self, load_default: bool = True) -> None:
        """
        Execute the tasks
        :param load_default: whether load default tasks or not
        :return: None
        """
        log.info('Start generating code...')
        start_time = time()
        mkdir(self.FILE_PATH_PREFIX)
        tasks = []
        if load_default:
            tasks = get_default_tasks()
        tasks += get_user_tasks()
        for task in tasks:
            write_file(self.FILE_PATH_PREFIX + task.filename, self.__data, task)
        elapsed_time_in_milliseconds = round(float(time() - start_time) * 1000, 1)
        log.info('Finished {} task(s) in {} seconds'.format(len(tasks), elapsed_time_in_milliseconds / 1000))
        log.info('Success!')
